import React, {PropsWithChildren, useCallback, useEffect, useMemo, useRef, useState} from 'react'
import {MultiMarker, TMap} from '@map-component/react-tmap';
import {AutoComplete, Select, Skeleton, Typography} from "antd";
import {
    searchPlaceRegion,
    SearchPlacePoiItemResponse,
    searchSuggestion,
    SearchSuggestionPoiItemResponse, SearchPlaceResponse, searchPlaceNearby
} from "../apis/TencentPositionApi";
import {debounce} from "@antv/util";
import {defaultPagination, Pageable, pageToPagination, paginationToPageable} from "../utils/Page";
import AdministrativeRegionCascader from "./AdministrativeRegionCascader";

export interface MapAddressSelectorValue {

    longitude: number

    latitude: number

    addressName: string

    address: string

    adcode: string
}

export interface MapAddressSelectorProps extends PropsWithChildren {
    value?: MapAddressSelectorValue
    onChange?: (v: MapAddressSelectorValue) => void
}

const PAGE_SIZE = 10
/**
 * 搜索地址，并给显示到地图中
 */
const MapAddressSelector: React.FC<MapAddressSelectorProps> = (props) => {
    const key = "4H5BZ-46KLN-TAIF6-SW45B-LTUAO-EVB3Q"
    const [scriptLoading, setScriptLoading] = useState(true)
    const mapIdRef = useRef(Date.now().toString());

    let [pagination, setPagination] = useState(defaultPagination({size: PAGE_SIZE}))


    const [poiList, setPoiList] = useState<SearchPlacePoiItemResponse[]>([])
    const [keyword, setKeyword] = useState("")
    useEffect(() => {
        setKeyword(props.value?.addressName ?? "")
    }, [props.value]);

    const [loading, setLoading] = useState(false)

    const [pageable, setPageable] = useState<Pageable>(paginationToPageable(pagination));
    const handlePopupScroll = useCallback((e: React.UIEvent<HTMLDivElement>) => {
        const {scrollTop, scrollHeight, clientHeight} = e.currentTarget;

        // 滚动到底部时加载下一页
        if (scrollHeight - scrollTop <= clientHeight + 20 && !loading && !pagination.last) {
            setPageable(prev => new Pageable(prev.page + 1, prev.size));
        }
    }, [pagination.last, loading]);

    const [districtCode, setDistrictCode] = useState<string>()

    const query = useCallback(() => {
        function handlePlaceData(data: SearchPlaceResponse) {
            setPoiList(prevState => prevState.concat(data.data ?? []))
            setPagination(prevState => {
                let total = data.count ?? 0;
                return {
                    ...prevState,
                    total: total,
                    page: pageable.page,
                    size: pageable.size,
                    first: pageable.page === 1,
                    last: total <= (pageable.page - 1) * pageable.size + (data.data?.length ?? 0),
                }
            })
        }

        if (keyword) {
            setLoading(true)
            if (districtCode) {
                searchPlaceRegion(keyword, districtCode, pageable).then(response => {
                    handlePlaceData(response.data);
                }).finally(() => {
                    setLoading(false)
                })
            } else {
                navigator.geolocation.getCurrentPosition(r => {
                    searchPlaceNearby(keyword, r.coords.longitude, r.coords.latitude, pageable).then(response => handlePlaceData(response.data)).finally(() => {
                        setLoading(false)
                    })
                })
            }
        } else {
            setPoiList([])
        }
    }, [districtCode, keyword, ...pageable.toDependencyList(),]);

    useEffect(() => {
        query()
    }, [query]);

    const handleSearch = useCallback(debounce((searchKeyword: string) => {
        setKeyword(searchKeyword)
        setPageable(new Pageable(1, PAGE_SIZE))
        setPoiList([])
        setPagination({
            ...pagination,
            last: false,
            first: true,
            total: 0,
        })
    }, 500), []);
    const marks: any[] = useMemo(() => {
        const array = []
        if (props.value) {
            array.push({
                position: {
                    lat: props.value.latitude,
                    lng: props.value.longitude,
                },
                content: props.value.address,
            } as never)
        }
        return array
    }, [props.value])

    const selectedValue = useMemo(() => {
        return props.value ? {lat: props.value.latitude, lng: props.value.longitude} : undefined
    }, [props.value?.longitude, props.value?.latitude]);

    const selectedValueString = useMemo(()=>{
        return selectedValue?`${selectedValue.lat},${selectedValue.lng}`:undefined
    },[selectedValue])

    return <>
        {scriptLoading ? <>
            <Skeleton.Input active={scriptLoading}/>
            <Skeleton.Input active={scriptLoading}/>
            <Skeleton.Node active={scriptLoading} style={{width: 400}}/>
        </> : <>
            <AdministrativeRegionCascader value={districtCode} onChange={value => setDistrictCode(value)}/>
            <Select style={{width: "100%", marginBottom: 16, marginTop: 16}} showSearch
                    placeholder={`搜索地址`}
                    value={selectedValueString} onSearch={handleSearch}
                    onPopupScroll={handlePopupScroll}
                    filterOption={false}
                    onChange={(v) => {
                        let poi = poiList.find(item => `${item.location.lat},${item.location.lng}`===v);
                        if (poi) {
                            props.onChange?.({
                                addressName: poi.title,
                                adcode: poi.ad_info.adcode,
                                ...poi,
                                longitude: poi.location.lng,
                                latitude: poi.location.lat,
                            })
                        }
                    }}  options={poiList.map(item => {
                return {
                    value: `${item.location.lat},${item.location.lng}`,
                    label: <div>
                        {item.title}
                        <span style={{width: 16, display: "inline-block"}}></span>
                        <Typography.Text
                            type={"secondary"}>{item.ad_info.province + item.ad_info.city + item.ad_info.district}</Typography.Text>
                    </div>,
                }
            })}/>

        </>}
        <TMap mapKey={key} version="1.exp" id={mapIdRef.current} center={selectedValue} onLoad={() => {
            setScriptLoading(false)
        }} control={{rotate: {position: "TOP_RIGHT"}}}>
            <MultiMarker geometries={marks} id={"marks"}/>
        </TMap>
    </>
}

export default MapAddressSelector


